package com.ziytek.web.citizen.service.impl;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.ziytek.web.citizen.configuration.db.DDS;
import com.ziytek.web.citizen.constant.DdsConstant;
import com.ziytek.web.citizen.constant.NumConstant;
import com.ziytek.web.citizen.constant.ServerConstant;
import com.ziytek.web.citizen.constant.SettingConstant;
import com.ziytek.web.citizen.enums.ResponseEnum;
import com.ziytek.web.citizen.enums.SchmeEnum;
import com.ziytek.web.citizen.enums.StepEnum;
import com.ziytek.web.citizen.event.StepSettingEvent;
import com.ziytek.web.citizen.mapper.BasicStepSettingsMapper;
import com.ziytek.web.citizen.model.bean.AddSettings;
import com.ziytek.web.citizen.model.bean.StepSettingsQueryResult;
import com.ziytek.web.citizen.model.req.StepSettingsAddReq;
import com.ziytek.web.citizen.model.req.StepSettingsModifyReq;
import com.ziytek.web.citizen.model.req.StepSettingsQueryReq;
import com.ziytek.web.citizen.model.rsp.StepSettingsQueryRsp;
import com.ziytek.web.citizen.pojo.basic.BasicStepSettings;
import com.ziytek.web.citizen.service.itf.StepSettingService;
import com.ziytek.web.citizen.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * @author fenghx
 * @version 1.0
 * @className StepSettingServiceImpl
 * Description:
 * @date 2024/3/15 10:13
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class StepSettingServiceImpl implements StepSettingService {
    private final Gson gson = new Gson();
    private final ApplicationContext context;
    private final BasicStepSettingsMapper stepSettingsMapper;

    @Override
    @DDS(DdsConstant.DS_BASIC)
    public String stepAdd(StepSettingsAddReq req, Long id, boolean addNew) {
        var returnCode = errorCode(req);
        if (!StepEnum.SUCCESS.getCode().equalsIgnoreCase(returnCode)) {
            // 工步设置异常
            return returnCode;
        }

        if (req.getLoopOrderBegin() == null) {
            req.setLoopOrderBegin(NumConstant.INT_ZERO);
        }
        if (req.getLoopOrderEnd() == null) {
            req.setLoopOrderEnd(NumConstant.INT_ZERO);
        }

        var planNo = req.getPlanNo();
        var time = req.getOperatorTime();
        var currentLimit = req.getChargeCurrentLimit();
        var voltageLimit = req.getChargeVoltageLimit();
        var disChargeCurrentLimit = req.getDisChargeCurrentLimit();
        var disChargeVoltageLimit = req.getDisChargeVoltageLimit();
        var name = StringUtil.isEmpty(req.getPlanName()) ? null : req.getPlanName().trim();

        var operatorTime = StringUtil.toLong(time);
        operatorTime = operatorTime <= NumConstant.LONG_ZERO ? System.currentTimeMillis() : operatorTime;

        if (addNew) {
            return settingsSave(ServerConstant.STEP_SETTING_TYPE_ADD, name, planNo, req.getIsLoop(), req.getOperatorId(),
                    currentLimit, voltageLimit, operatorTime, disChargeCurrentLimit, disChargeVoltageLimit,
                    gson.toJson(req.getSettingList()), req.getOpenCircuitVoltageLimit1(), req.getOpenCircuitVoltageLimit2(),
                    req.getLoopOrderBegin(), req.getLoopOrderEnd());
        }

        id = id != null && id > NumConstant.LONG_ZERO ? id : NumConstant.LONG_LT_TEN;
        var step = stepSettingsMapper.findFirstById(id);
        if (step == null || SettingConstant.IS_NORMAL != step.getIsDelete()) {
            step = stepSettingsMapper.findFirstByPlanNoAndIsDeleteOrderByCreateTimeDesc(planNo, SettingConstant.IS_NORMAL);
        }

        // 对象不存在
        if (step == null) {
            return StepEnum.OBJECT_NOT_EXIST.getCode();
        }

        // 不是新增方案，修改方案
        var oldStep = stepSettingsMapper.findFirstByPlanNameAndIsDeleteOrderByCreateTimeDesc(name, SettingConstant.IS_NORMAL);
        // 新增方案名称不能重复
        if (oldStep != null && !oldStep.getId().equals(step.getId())) {
            return StepEnum.UPDATE_NAME_ERROR.getCode();
        }

        // 修改的，老的先注销，再新增

        var del = stepDel(step.getId());
        if (del <= NumConstant.INT_ZERO) {
            return StepEnum.MODIFY_ERROR.getCode();
        }

        // 重新新增一笔工步方案
        var modify = settingsSave(ServerConstant.STEP_SETTING_TYPE_MODIFY, name, planNo, req.getIsLoop(), req.getOperatorId(),
                currentLimit, voltageLimit, operatorTime, disChargeCurrentLimit, disChargeVoltageLimit,
                gson.toJson(req.getSettingList()), req.getOpenCircuitVoltageLimit1(), req.getOpenCircuitVoltageLimit2(),
                req.getLoopOrderBegin(), req.getLoopOrderEnd());

        if (!StepEnum.SUCCESS.getCode().equalsIgnoreCase(modify)) {
            return StepEnum.MODIFY_ERROR.getCode();
        }

        return StepEnum.SUCCESS.getCode();
    }

    @Override
    @DDS(DdsConstant.DS_BASIC)
    public String stepModify(StepSettingsModifyReq req) {
        var idStr = req.getId();
        var id = StringUtil.toLong(idStr);
        var set = stepSettingsMapper.findFirstById(id);
        if (set == null || SettingConstant.IS_NORMAL != set.getIsDelete()) {
            // 工步方案不存在
            return StepEnum.OBJECT_NOT_EXIST.getCode();
        }

        // 新增新配置
        var add = new StepSettingsAddReq();
        BeanUtils.copyProperties(req, add);
        return stepAdd(add, id, false);
    }

    private void fillStepSettings(BasicStepSettings step, String name, String planNo, int loop, String operatorId, int currentLimit,
                                  int voltageLimit, long operatorTime, int disChargeCurrentLimit, int disChargeVoltageLimit,
                                  String settingList, int openCircuitVoltageLimit1, int openCircuitVoltageLimit2) {
        // 是否循环
        step.setIsLoop(loop);
        step.setPlanName(name);
        step.setPlanNo(planNo);
        step.setOperatorId(operatorId);
        step.setStepSettings(settingList);
        step.setOperatorTime(operatorTime);
        step.setChargeCurrentLimit(currentLimit);
        step.setChargeVoltageLimit(voltageLimit);
        step.setIsDelete(SettingConstant.IS_NORMAL);
        // 启用
        step.setLoopOrderEnd(step.getLoopOrderEnd());
        step.setUpdateTime(System.currentTimeMillis());
        step.setLoopOrderBegin(step.getLoopOrderBegin());
        step.setDisChargeCurrentLimit(disChargeCurrentLimit);
        step.setDisChargeVoltageLimit(disChargeVoltageLimit);
        step.setOpenCircuitVoltageLimit1(openCircuitVoltageLimit1);
        step.setOpenCircuitVoltageLimit2(openCircuitVoltageLimit2);
    }

    @Override
    @DDS(DdsConstant.DS_BASIC)
    public int stepDel(Long id) {
        if (id == null || id <= NumConstant.LONG_ZERO) {
            return NumConstant.INT_ZERO;
        }
        BasicStepSettings step;
        try {
            step = stepSettingsMapper.findFirstById(id);
            var isNormal = step != null && SettingConstant.IS_NORMAL == step.getIsDelete();
            if (isNormal) {
                step.setIsDelete(SettingConstant.IS_DELETE);
                step.setUpdateTime(System.currentTimeMillis());
                stepSettingsMapper.settingsUpdate(SettingConstant.IS_DELETE, System.currentTimeMillis(), step.getId());
            }
        } catch (Exception e) {
            log.error("删除工步方案失败:{},", id, e);
            return NumConstant.INT_ZERO;
        }

        // 发送工步方案更新事件
        context.publishEvent(new StepSettingEvent(ServerConstant.STEP_SETTING_TYPE_DELETE, step == null ? null : step.getId(), 0,
                0, 0, step == null ? null : step.getStepSettings()));
        return NumConstant.INT_ONE;
    }

    @Override
    @DDS(DdsConstant.DS_BASIC)
    public StepSettingsQueryRsp stepQuery(StepSettingsQueryReq req) {
        var response = new StepSettingsQueryRsp();
        response.setRetCode(ResponseEnum.SUCCESS.getCode());
        response.setRetMsg(ResponseEnum.SUCCESS.getDesc());
        var list = req.getId() == null ? stepSettingsMapper.findByIsDeleteOrderByCreateTimeAsc(SettingConstant.IS_NORMAL) : null;
        if (CollectionUtils.isEmpty(list)) {
            var stepSettingsTable = stepSettingsMapper.findFirstByIdAndIsDelete(req.getId(), SettingConstant.IS_NORMAL);
            if (stepSettingsTable == null) {
                return response;
            }

            list = new ArrayList<>();
            list.add(stepSettingsTable);
        }

        List<StepSettingsQueryResult> results = new ArrayList<>();
        for (var sp : list) {
            var result = new StepSettingsQueryResult();
            BeanUtils.copyProperties(sp, result);
            result.setIsLoop(sp.getIsLoop());
            result.setId(String.valueOf(sp.getId()));
            result.setLoopOrderEnd(sp.getLoopOrderEnd());
            result.setLoopOrderBegin(sp.getLoopOrderBegin());
            result.setSettingList(gson.fromJson(sp.getStepSettings(), new TypeToken<List<AddSettings>>() {
            }.getType()));
            result.getSettingList().sort(Comparator.comparing(AddSettings::getSettingOrder));
            results.add(result);
        }

        response.setData(results);
        return response;
    }

    private String setError(List<AddSettings> list, int currentLimit) {
        if (CollectionUtils.isEmpty(list)) {
            return StepEnum.SET_LIST_EMPTY.getCode();
        }

        for (var a : list) {
            if (a == null) {
                continue;
            }

            var type = a.getSetType();
            // 恒流恒压充电 电流电压均不能为空,截止数据类型为电流
            if (SettingConstant.CONSTANT_CURRENT_CONSTANT_VOLTAGE.equalsIgnoreCase(type)) {
                Integer c = a.getCurrent();
                Integer v = a.getVoltage();
                Integer co = a.getCutOff();
                String t = a.getCutOffType();
                if (StringUtil.hasOneEmpty(c, v, co, t) || !SettingConstant.CUT_OFF_TYPE_CURRENT.equals(t)) {
                    return StepEnum.CCV_ERROR.getCode();
                }
            }
            // 恒流充电 电流不能为空,截止数据类型为电压
            if (SettingConstant.CONSTANT_CURRENT.equalsIgnoreCase(type)) {
                Integer c = a.getCurrent();
                Integer co = a.getCutOff();
                String t = a.getCutOffType();
                if (StringUtil.hasOneEmpty(c, co, t) || !SettingConstant.CUT_OFF_TYPE_VOLTAGE.equals(t)) {
                    return StepEnum.CC_ERROR.getCode();
                }
            }
            // 恒压充电 电压不能为空,截止数据类型为电流
            if (SettingConstant.CONSTANT_VOLTAGE.equalsIgnoreCase(type)) {
                Integer v = a.getVoltage();
                Integer co = a.getCutOff();
                String t = a.getCutOffType();
                if (StringUtil.hasOneEmpty(v, co, t) || !SettingConstant.CUT_OFF_TYPE_CURRENT.equals(t)) {
                    return StepEnum.CC_ERROR.getCode();
                }
            }
            // 恒流放电 电流不能为空,截止数据类型为电压
            if (SettingConstant.CONSTANT_CURRENT_DISCHARGE.equalsIgnoreCase(type)) {
                Integer c = a.getCurrent();
                Integer co = a.getCutOff();
                String t = a.getCutOffType();
                if (StringUtil.hasOneEmpty(c, co, t) || !SettingConstant.CUT_OFF_TYPE_VOLTAGE.equals(t)) {
                    return StepEnum.CCD_ERROR.getCode();
                }
            }

            // 恒流放电 ((前端截止电压传值*i=功率值) i<最大充电限制电流)
            if (SettingConstant.CONSTANT_POWER_DISCHARGE.equalsIgnoreCase(type)) {
                var p = a.getVoltage();
                var cfV = a.getCutOff();
                var ci = (p * NumConstant.INT_ONE_THOUSAND) / cfV;
                if (ci >= currentLimit) {
                    return StepEnum.CPD_ADD_ERROR.getCode();
                }
            }
        }

        return StepEnum.SUCCESS.getCode();
    }

    private String setLoopError(StepSettingsAddReq req) {
        if (req == null || req.getIsLoop() == null || req.getIsLoop() < NumConstant.INT_ZERO) {
            return StepEnum.REQUEST_PARAMETER_ERROR.getCode();
        }

        // 工步不循环
        if (req.getIsLoop() == NumConstant.INT_ZERO) {
            req.setLoopOrderEnd(NumConstant.INT_ZERO);
            req.setLoopOrderBegin(NumConstant.INT_ZERO);
            return StepEnum.SUCCESS.getCode();
        }

        var loop = req.getIsLoop();
        var loopOrderBegin = req.getLoopOrderBegin() != null ? req.getLoopOrderBegin() : NumConstant.INT_ZERO;
        var loopOrderEnd = req.getLoopOrderEnd() != null ? req.getLoopOrderEnd() : NumConstant.INT_ZERO;
        var loopError = loopOrderEnd > NumConstant.INT_ZERO && loopOrderEnd < loopOrderBegin;
        if (loopError) {
            // 工步循环设置异常
            return StepEnum.STEP_LOOP_SET_FAILED.getCode();
        }
        return StepEnum.SUCCESS.getCode();
    }

    private String errorCode(StepSettingsAddReq req) {
        if (req == null) {
            return ResponseEnum.PARAMETER_ERROR.getCode();
        }

        var currentLimit = req.getChargeCurrentLimit();
        var voltageLimit = req.getChargeVoltageLimit();
        var disChargeCurrentLimit = req.getDisChargeCurrentLimit();
        var disChargeVoltageLimit = req.getDisChargeVoltageLimit();
        var name = StringUtil.isEmpty(req.getPlanName()) ? null : req.getPlanName().trim();
        if (StringUtil.hasOneEmpty(name)) {
            return StepEnum.NAME_NOT_EXIST.getCode();
        }

        if (StringUtil.hasOneEmpty(currentLimit, voltageLimit, disChargeCurrentLimit, disChargeVoltageLimit)) {
            // 保护参数设置不正确
            return StepEnum.PROTECTION_SET_PARAMETER_ERROR.getCode();
        }

        if (CollectionUtils.isEmpty(req.getSettingList())) {
            // 工步设置不能为空
            return StepEnum.SET_LIST_EMPTY.getCode();
        }

        if (req.getSettingList().size() > NumConstant.INT_ONE_HUNDRED) {
            // 工步列表数量上限不能大于100
            return StepEnum.LIST_COUNT_OUT.getCode();
        }

        var code = setError(req.getSettingList(), currentLimit);
        if (!StepEnum.SUCCESS.getCode().equalsIgnoreCase(code)) {
            // 工步设置异常
            return StepEnum.SET_LIST_ERROR.getCode();
        }

        var loopCode = setLoopError(req);
        if (!StepEnum.SUCCESS.getCode().equalsIgnoreCase(loopCode)) {
            // 工步循环设置异常
            return StepEnum.STEP_LOOP_SET_FAILED.getCode();
        }

        return StepEnum.SUCCESS.getCode();
    }

    private String settingsSave(int flag, String name, String planNo, int loop, String operatorId, int currentLimit,
                                int voltageLimit, long operatorTime, int disChargeCurrentLimit, int disChargeVoltageLimit,
                                String settingList, int openCircuitVoltageLimit1, int openCircuitVoltageLimit2, int loopOrderBegin, int loopOrderEnd) {

        var nameStep = stepSettingsMapper.findFirstByPlanNameAndIsDeleteOrderByCreateTimeDesc(name, SettingConstant.IS_NORMAL);
        var planNoStep = stepSettingsMapper.findFirstByPlanNoAndIsDeleteOrderByCreateTimeDesc(planNo, SettingConstant.IS_NORMAL);

        // 新增方案名称不能重复
        if (nameStep != null) {
            return StepEnum.UPDATE_NAME_ERROR.getCode();
        }
        // 新增方案名称不能重复
        if (planNoStep != null) {
            return StepEnum.UPDATE_NO_ERROR.getCode();
        }

        var step = new BasicStepSettings();
        step.setCreateTime(System.currentTimeMillis());
        var newId = stepSettingsMapper.queryMaxId();
        step.setId(newId == null ? NumConstant.LONG_ONE : newId);
        step.setLoopOrderEnd(loopOrderEnd);
        step.setLoopOrderBegin(loopOrderBegin);

        try {
            fillStepSettings(step, name, planNo, loop, operatorId,
                    currentLimit, voltageLimit, operatorTime, disChargeCurrentLimit, disChargeVoltageLimit,
                    settingList, openCircuitVoltageLimit1, openCircuitVoltageLimit2);

            stepSettingsMapper.settingsSave(step);
        } catch (Exception e) {
            log.error("工步方案新增异常:{},", step, e);
            return SchmeEnum.ADD_ERROR.getCode();
        }

        // 发送工步方案更新事件
        context.publishEvent(new StepSettingEvent(flag, step.getId(), loop, loopOrderBegin, loopOrderEnd, settingList));
        return StepEnum.SUCCESS.getCode();
    }
}
